package com.roc.template.mongo.config;

import com.mongodb.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.convert.MongoTypeMapper;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName MongoConfig
 * @Description: TODO
 * @Author Administrator
 * @Date 2020/7/15 17 33
 * @Version V1.0
 **/
@Configuration
public class MongoConfig {

    @Value("${mongo.username}")
    private String username;
    @Value("${mongo.password}")
    private String password;
    @Value("${mongo.dbname}")
    private String database;
    @Value("${mongo.authdbname}")
    private String authdb;
    @Value("${mongo.ossDev.replicaSet}")
    private String replicaSet;
    @Value("${mongo.connectionsPerHost}")
    private int connectionPerHost;
    @Value("${mongo.threadsAllowedToBlockForConnectionMultiplier}")
    private int threads;
    @Value("${mongo.connectTimeout}")
    private int connectTimeout;
    @Value("${mongo.maxWaitTime}")
    private int maxWaitTime;
    @Value("${mongo.socketTimeout}")
    private int socketTimeout;

    @Bean
    public MongoClient mongoClient() {
        List<ServerAddress> serverAddresses = parseReplicaSet();
        List<MongoCredential> credentialList = credential();
        MongoClientOptions options = mongoClientOptions();
        if (null == credentialList) {
            return new MongoClient(serverAddresses, options);
        }
        return new MongoClient(serverAddresses, credentialList, options);
    }

    private MongoClientOptions mongoClientOptions() {
        return MongoClientOptions.builder()
                .connectionsPerHost(connectionPerHost)
                .threadsAllowedToBlockForConnectionMultiplier(threads)
                .connectTimeout(connectTimeout)
                .maxWaitTime(maxWaitTime)
                .socketTimeout(socketTimeout)
                .build();
    }

    private List<MongoCredential> credential() {
        if ((!username.equals("")) && (!password.equals("")) && (!authdb.equals(""))) {
            char[] pass = password.toCharArray();
            MongoCredential credential = MongoCredential.createCredential(username, authdb, pass);
            List<MongoCredential> credentialList = new ArrayList<>();
            credentialList.add(credential);
            return credentialList;
        }
        return null;
    }

    private List<ServerAddress> parseReplicaSet() {
        if (replicaSet==null) {
            throw new IllegalArgumentException("mongodb replicaset配置格式错误:" + replicaSet);
        }

        String[] replicas = replicaSet.trim().split(",");
        List<ServerAddress> serverAddressList = new ArrayList<>(replicas.length);
        for (String replica : replicas) {
            String[] hostAndPort = replica.split(":");
            serverAddressList.add(new ServerAddress(hostAndPort[0], Integer.parseInt(hostAndPort[1])));
        }
        return serverAddressList;
    }

    @Bean
    public MongoDbFactory mongoDbFactory(MongoClient mongoClient) throws UnknownHostException {
        return new SimpleMongoDbFactory(mongoClient, database);
    }

    @Bean
    public MongoMappingContext mappingContext() {
        return new MongoMappingContext();
    }

    @Bean
    public MappingMongoConverter mappingMongoConverter(MongoDbFactory mongoDbFactory, MongoMappingContext mappingContext, MongoTypeMapper typeMapper) {
        // 以下1行代码用于避免mongotemplate将符合ObjectId格式的字符串主键转换为ObjectId对象来存储
//        MappingMongoConverter mappingMongoConverter = new CloudFormMappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), mappingContext);
        MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), mappingContext);
        mappingMongoConverter.setTypeMapper(typeMapper);
        return mappingMongoConverter;
    }

    @Bean
    public DefaultMongoTypeMapper defaultMongoTypeMapper() {
        return new DefaultMongoTypeMapper(null);
    }

    @Bean
    public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory, MappingMongoConverter mappingMongoConverter) {
        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, mappingMongoConverter);
        //mongoTemplate.setReadPreference(secondaryPreferredReadPreference(tagSetObject(tagObject())));
//        mongoTemplate.setReadPreference(ReadPreference.secondary());
        mongoTemplate.setReadPreference(ReadPreference.primary());

        // 以下3行代码用于避免查询时mongotemplate将符合ObjectId格式的字符串主键当作ObjectId来查询
//        Field queryMapper = ReflectionUtils.findField(MongoTemplate.class, "queryMapper");
//        queryMapper.setAccessible(true);
//        ReflectionUtils.setField(queryMapper, mongoTemplate, new CloudFormQueryMapper(mappingMongoConverter));
        return mongoTemplate;
    }

}
